package dalgo.utils;

import java.util.ArrayList;

import uniandes.cupi2.collections.arbol.arbolBinario.ArbolBinario;
import uniandes.cupi2.collections.arbol.arbolBinario.NodoArbolBinario;
import uniandes.cupi2.collections.colaEncadenada.ColaEncadenada;
import dalgo.main.Main;
import dalgo.reglas.Regla;

public class Utils {

	/**
	 * Hace la copia de un arbol binario en otro arbol biniario
	 * 
	 * @param original
	 *            el arbol binario original
	 * @return la copia del arbol dado
	 */
	public static ArbolBinario<String> copiarArbol(ArbolBinario<String> original) {

		String elem = original.darRaiz().darElemento();

		NodoArbolBinario<String> nuevaRaiz = new NodoArbolBinario<String>(elem);

		if (original.darRaiz().darDerecho() != null) {
			nuevaRaiz.encadenarDerecho(copiarNodo(original.darRaiz()
					.darDerecho()));
		}
		if (original.darRaiz().darIzquierdo() != null) {

			nuevaRaiz.encadenarIzquierdo(copiarNodo(original.darRaiz()
					.darIzquierdo()));
		}

		ArbolBinario<String> arbol = new ArbolBinario<String>();
		arbol.definirRaiz(nuevaRaiz);
		return arbol;

	}

	/**
	 * Relaiza la copia de un nodo de arbol binario
	 * 
	 * @param original
	 *            nodo de arbol binario original
	 * @return la copia del nodo original
	 */
	public static NodoArbolBinario<String> copiarNodo(
			NodoArbolBinario<String> original) {

		String elem = original.darElemento();

		NodoArbolBinario<String> nuevoNodo = new NodoArbolBinario<String>(elem);
		if (original.darDerecho() != null) {
			nuevoNodo.encadenarDerecho(copiarNodo(original.darDerecho()));
		}
		if (original.darIzquierdo() != null) {
			nuevoNodo.encadenarIzquierdo(copiarNodo(original.darIzquierdo()));
		}
		return nuevoNodo;
	}

	
	
	/**
	 * Pregunta si el nodo (de arbol) es un operador binario, es decir, suma,
	 * resta, multiplicacion, division e igualdad
	 * 
	 * @param op
	 *            operador a verificar
	 * @return <code>true</code> si es un operador binario, <code>false</code>
	 *         de lo contrario
	 */
	public static boolean esBinario(String op) {
		if (op.equals(Regla.SUMA) || op.equals(Regla.RESTA)
				|| op.equals(Regla.MULTIPLICACION) || op.equals(Regla.DIVISION)
				|| op.equals("="))
			return true;
		else
			return false;
	}

	/**
	 * Pregunta si el nodo (de arbol) es un operador unario, es decir, raiz,
	 * cuadrado, logaritmo y la funcion inversa de logaritmo
	 * 
	 * @param op
	 *            operador a verificar
	 * @return <code>true</code> si es un operador binario, <code>false</code>
	 *         de lo contrario
	 */
	public static boolean esUnario(String op) {
		if (op.equals(Regla.RAIZ) || op.equals(Regla.CUADRADO)
				|| op.equals(Regla.LOG) || op.equals(Regla.INVLOG))
			return true;
		else
			return false;

	}

	/**
	 * Cuenta cuantas variables hay en el arbol de este estado, usado para la
	 * calculacion de la heuristica, metodo recursivo
	 * 
	 * @param cant
	 *            cantidad de variables inicial
	 * @param nodo
	 *            nodo a evaluar
	 * @return el numero de variables del arbol
	 */
	public static int contarCantVariables(
			NodoArbolBinario<String> nodo) {

		int cant= 0;
		if (nodo.darElemento().equals(Main.getVariable())) {
			cant++;
			
		}  if (nodo.darIzquierdo() != null) {

			cant+= contarCantVariables(nodo.darIzquierdo());
		} if (nodo.darDerecho() != null) {

			cant+= contarCantVariables(nodo.darDerecho());
		}
			return cant;

	}

	/**
	 * Metodo que verifica si existe la variable en ambas ramas del arbol
	 * 
	 * @param variable
	 *            la variable a buscar en las ramas
	 * @return <code>true</code> si la variable esta en una sola de las ramas,
	 *         izquierda o derecha, <code>false</code> si esta en ambas ramas
	 */
	public static boolean variableSola(String variable,
			ArbolBinario<String> arbol) {

		// false si la variable esta en ambas ramas
		boolean hayVariable = false;
		NodoArbolBinario<String> raiz = arbol.darRaiz();
		if (raiz.darIzquierdo() != null) {
			hayVariable = hayVariable(variable, raiz.darIzquierdo());
		}
		if (raiz.darDerecho() != null) {
			hayVariable = !(hayVariable && hayVariable(variable, arbol
					.darRaiz().darDerecho()));
		}
		return hayVariable;
	}

	/**
	 * Metodo recursivo que mira si en el nodo pasado como parametro tiene la
	 * variable buscada
	 * 
	 * @param variable
	 *            la variable a buscar
	 * @param nodo
	 *            el nodo del arbol a evaluar
	 * @return <code>true</code> si tiene la variable, <code>false</code> de lo
	 *         contrario
	 */
	public static boolean hayVariable(String variable,
			NodoArbolBinario<String> nodo) {

		if (nodo.darElemento().equals(variable)) {
			return true;
		} else {
			if (nodo.darIzquierdo() != null) {
				if( hayVariable(variable, nodo.darIzquierdo()))
					return true;
			}
			if (nodo.darDerecho() != null) {
				if( hayVariable(variable, nodo.darDerecho()))
					return true;
			}
			return false;
		}
	}
	
	
	

}
